#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#define SIZE 512
#define SkipPath(p) do{ p += strlen(p)-1; while(*p != '/') p--;}while(0)
#define NUM 32

char* gArgv[NUM];
char cwd[SIZE*2];
int lastcode = 0;

const char* GetUserName()
{
	const char* s = getenv("USER");
	if (s == NULL) return "None";
	return s;
}

const char* GetHostName()
{
	const char* s = getenv("HOSTNAME");
	if (s == NULL) return "None";
	return s;
}

const char* GetPwd()
{
	const char* s = getenv("PWD");
	if (s == NULL) return "None";
	return s;
}

void MakeCommandAndPrint()
{
	char line[SIZE];

	const char* username = GetUserName();
	const char* hostname = GetHostName();
	const char* cwd = GetPwd();
  
  SkipPath(cwd);
	snprintf(line, sizeof(line), "[%s@%s %s]> ", username, hostname, strlen(cwd) == 1 ? "/" : cwd+1);
	printf("%s", line);
  fflush(stdout);
}

int GetUserCommand(char usercommand[], int n)
{
  char* s =fgets(usercommand, n, stdin);
  if (s == NULL) return -1;

  usercommand[strlen(usercommand)-1] = '\0'; // 去除换行符
  return strlen(usercommand);
}

void CommandSplit(char usercommand[])
{
  gArgv[0] = strtok(usercommand, " ");

  int i = 1;
  while(1)
  {
    gArgv[i] = strtok(NULL, " ");
    if (gArgv[i] == NULL)
      break;
    i++;
  }
}

const char* GetHome()
{
  const char* home = getenv("HOME");
  if (home == NULL)
    return "None";
  return home;
}

void Cd()
{
  const char* path = gArgv[1];
  if (path == NULL)
    path = GetHome();
  //到这里 path 一定存在
  chdir(path);

  // 改变环境变量
  char tmp[SIZE*2];
  getcwd(tmp, sizeof(tmp));
  snprintf(cwd, sizeof(cwd), "PWD=%s", tmp);
  putenv(cwd);
  
}

int CheckBuildin()
{
  const char* enter_cmd = gArgv[0];
  int yes = 0;
  if (strcmp(enter_cmd, "cd") == 0)
  {
    yes = 1;
    Cd();
    lastcode = 0;
  }
  else if(strcmp(gArgv[0], "echo") == 0 && strcmp(gArgv[1], "$?") == 0)
  {
    yes = 1;
    printf("%d\n", lastcode);
    lastcode = 0;
  }
  return yes;
}
void ExecuteCmd()
{
  pid_t id = fork();
  if (id < 0) exit(1);
  else if (id == 0)
  {
    // child
    execvp(gArgv[0], gArgv);
    exit(errno); // 执行失败
  }
  // father
  int status = 0;
  pid_t rid = waitpid(id, &status, 0);
  if (rid > 0)
  {
    // wait sucess
    lastcode = WEXITSTATUS(status);
    if (lastcode)
      printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode);
  }
}
int main()
{
  int quit = 0;
  while(!quit)
  {  
    	// 输出命令行
    	MakeCommandAndPrint();
      
      // 获取用户输入命令
      char usercommand[SIZE];
      int n = GetUserCommand(usercommand, sizeof(usercommand));
      if (n <= 0) return 1;
    
      // 分割命令行字符串
      CommandSplit(usercommand);

      // 检测内建命令
      n = CheckBuildin();
      if (n) continue; // 父进程执行内建命令后，就不用子进程执行了
      
      // 执行命令
      ExecuteCmd();
  }
	return 0;
}
